#include "ComponentWalkAroundBehavior.h"
#include "Components/ComponentCreature.h"
#include "Components/ComponentBody.h"
#include "Components/ComponentCreatureSounds.h"
#include "ComponentPathfinding.h"
#include "Managers/GameManager.h"
#include "Subsystems/SubsystemTerrain.h"

#include "GameRandom.hpp"
#include "GameSingleton.h"
#include "GameRegistry.hpp"
#include "GameThreadPool.hpp"


namespace PocketSurvival
{

    // ************** 【状态机】 **************

    ComponentWalkAroundBehavior::StateMachine::StateMachine(ComponentWalkAroundBehavior *walkAround) : m_walkAround(walkAround), EasyMachine(MachineState::Inactive) 
    {
        enter();
    }

    void ComponentWalkAroundBehavior::StateMachine::enter()
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            m_walkAround->m_importanceLevel = GameSingleton::gameRandom->getFloat(0.0f, 1.0f);
            break;
        case MachineState::Walk:
            float speed = (m_walkAround->componentCreature->componentBody->immersionFactor > 0.5f ? 1.0f : GameSingleton::gameRandom->getFloat(0.25f, 0.35f));
            m_walkAround->componentPathfinding->setDestination(m_walkAround->findDestination(), speed, 1.0f, 0, false, true, false, nullptr);
            break;
        }
    }

    void ComponentWalkAroundBehavior::StateMachine::update(float dt)
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            MACHINE_DELEGATE()
            {
                if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.5f * dt)
                {
                    m_walkAround->m_importanceLevel = GameSingleton::gameRandom->getFloat(1.0f, 2.0f);
                }
                if (m_walkAround->isActive())
                {
                    changeTo(MachineState::Walk);
                }
            }
            break;
        case MachineState::Walk:
            MACHINE_DELEGATE()
            {
                if (m_walkAround->componentPathfinding->isStuck || m_walkAround->isActive() == false)
                {
                    changeTo(MachineState::Inactive);
                }
                if (m_walkAround->componentPathfinding->destination == FastVector3::Zero)
                {
                    if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.5f)
                    {
                        changeTo(MachineState::Inactive);
                    }
                    else
                    {
                        float speed = (m_walkAround->componentCreature->componentBody->immersionFactor > 0.5f ? 1.0f : GameSingleton::gameRandom->getFloat(0.25f, 0.35f));
                        m_walkAround->componentPathfinding->setDestination(m_walkAround->findDestination(), speed, 1.0f, 0, false, true, false, nullptr);
                    }
                }
                if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.1f * dt)
                {
                    // m_walkAround->componentCreature->componentCreatureSounds->playIdleSound(false);
                }
            }
            break;
        }
    }

    void ComponentWalkAroundBehavior::StateMachine::leave() {}

    // **************************************


    ComponentWalkAroundBehavior::~ComponentWalkAroundBehavior()
    {
        delete m_stateMachine;
    }

    float ComponentWalkAroundBehavior::getImportanceLevel()
    {
        return m_importanceLevel;
    }

    Vector3 ComponentWalkAroundBehavior::findDestination()
    {
        SubsystemTerrain *terrain = GameSingleton::singletonPtr->getSingleton<SubsystemTerrain>();

        Vector3 position;
        componentCreature->componentBody->getPosition(position);

        float num = 0.0f;
        Vector3 result = position;
        for(int32_t index = 0; index < 16; index++)
        {
            Vector2 vector = Vector2::Normalize(GameSingleton::gameRandom->getVector2(1.0f) * GameSingleton::gameRandom->getFloat(6.0f, 12.0f));
            Vector3 vector2(position.posX + vector.posX, 0.0f, position.posZ + vector.posY);
            vector2.posY = terrain->getTopHeight(Terrain::ToCell(vector2.posX), Terrain::ToCell(vector2.posZ)) + 1;
            float num2 = scoreDestination(vector2);
            if(num2 > num)
            {
                num = num2;
                result = vector2;
            }
        }
        return result;
    }
    
    float ComponentWalkAroundBehavior::scoreDestination(const Vector3 &destination)
    {
        Vector3 position;
        componentCreature->componentBody->getPosition(position);

        float num = 8.0f - MathUtils::Abs<float>(position.posY - destination.posY);
        if(GameSingleton::singletonPtr->getSingleton<SubsystemTerrain>()->getCellContents(Terrain::ToCell(destination.posX), Terrain::ToCell(destination.posY) - 1, Terrain::ToCell(destination.posZ)) == 18)
        {
            num -= 0.5f;
        }
        return num;
    }



    void ComponentWalkAroundBehavior::update(float dt)
    {
        m_stateMachine->update(dt);
    }

    static const std::string componentName = "WalkAroundBehavior";
    const std::string &ComponentWalkAroundBehavior::getName() const
    {
        return componentName;
    }
    const std::string &ComponentWalkAroundBehavior::GetName()
    {
        return componentName;
    }
    void ComponentWalkAroundBehavior::load(const nlohmann::json &jsonData)
    {
        componentCreature = GameSingleton::gameRegistry->get<ComponentCreature*>(entity);
        componentPathfinding = GameSingleton::gameRegistry->get<ComponentPathfinding*>(entity);

        m_stateMachine = new StateMachine(this);
    }

}

